﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Collections.TreeCollections;
using FeatureModelCore.FMTypes;
using System.Xml.Linq;
using FeatureModelCore.FMInterface;
using Collections;
using FeatureModelCore.FeatureModelEventArgs;

namespace FeatureModelCore.FMCrossTreeConstraint
{
    public class CrossTreeConstraint : IConstraint
    {
        #region Xml Symbol
        private readonly static string _XML_ID = "ID";
        private readonly static string _XML_TYPE = "CrossTreeConstraintType";
        private readonly static string _XML_IDA = "IdentifyA";
        private readonly static string _XML_IDB = "IdentifyB";
        #endregion

        #region Properties
        public TreeNodeIdentify ID { get { return _id; } }

        /// <summary>
        /// Feature Model
        /// </summary>
        public Tree Tree
        {
            get { return _belongToFeatureModel; }
            internal set { _belongToFeatureModel = (FeatureModelTree)value; }
        }
        public IFeature NodeA { get { return (IFeature)_belongToFeatureModel[_nodeIdA]; } }
        public IFeature NodeB { get { return (IFeature)_belongToFeatureModel[_nodeIdB]; } }
        public TreeNodeIdentify NodeIDA { get { return _nodeIdA; } }
        public TreeNodeIdentify NodeIDB { get { return _nodeIdB; } }
        public FMCrossTreeConstraintType Type
        {
            get { return _type; }
            set
            {
                string info = string.Format("Modify Cross Constraint Type to '{0}'"
                    , value.ToString());

                ConstraintModifiedEventArgs e = new ConstraintModifiedEventArgs(
                    this, info, 0, _type, value);

                this._belongToFeatureModel.PreProcess(this, e);
                _type = value;
                this._belongToFeatureModel.PreProcess(this, e);
            }
        }
        public string Name { get { return this.ToString(); } }
        #endregion

        #region Fields
        private TreeNodeIdentify _id;
        private FeatureModelTree _belongToFeatureModel;

        private TreeNodeIdentify _nodeIdA;
        private TreeNodeIdentify _nodeIdB;
        private FMCrossTreeConstraintType _type;

        private bool _existError;
        private FMSet<ErrorType> _errorMessages;
        private bool _existWarning;
        private FMSet<WarningType> _warningMessages;
        #endregion


        internal CrossTreeConstraint(TreeNodeIdentify id
            , FMCrossTreeConstraintType type,
            TreeNodeIdentify idA, TreeNodeIdentify idB)
        {
            _id = id;

            _nodeIdA = idA;
            _nodeIdB = idB;
            _type = type;

            _existError = false;
            _errorMessages = new FMSet<ErrorType>();
            _existWarning = false;
            _warningMessages = new FMSet<WarningType>();
        }

        /// <summary>
        /// Valid Cross Tree Constraint
        /// </summary>
        /// <returns></returns>
        public bool Valid()
        {
            TreeObject obj = this._belongToFeatureModel[_nodeIdA];
            if (obj == null)
            {
                return false;
            }
            obj = this._belongToFeatureModel[_nodeIdA];
            if (obj == null)
            {
                return false;
            }
            return true;
        }

        #region Xml Parser
        /// <summary>
        /// Xml Parser
        /// </summary>
        /// <returns></returns>
        public XElement ToXElem()
        {
            XElement xelem = new XElement(this.GetType().Name);
            xelem.Add(new XAttribute(_XML_ID, _id.ToString()));
            xelem.Add(new XAttribute(_XML_IDA, _nodeIdA.ToString()));
            xelem.Add(new XAttribute(_XML_IDB, _nodeIdB.ToString()));
            xelem.Add(new XAttribute(_XML_TYPE, _type.ToString()));

            return xelem;
        }
        /// <summary>
        /// Xml Parser
        /// </summary>
        /// <param name="xelem"></param>
        /// <returns></returns>
        public static CrossTreeConstraint XmlParser(XElement xelem)
        {
            string idStr = xelem.Attribute(_XML_ID).Value;

            string idAStr = xelem.Attribute(_XML_IDA).Value;
            string idBStr = xelem.Attribute(_XML_IDB).Value;
            string typeStr = xelem.Attribute(_XML_TYPE).Value;

            TreeNodeIdentify id = new TreeNodeIdentify(idStr);
            TreeNodeIdentify idA = new TreeNodeIdentify(idAStr);
            TreeNodeIdentify idB = new TreeNodeIdentify(idBStr);
            FMCrossTreeConstraintType type = (FMCrossTreeConstraintType)Enum.Parse(
                typeof(FMCrossTreeConstraintType), typeStr, true);

            CrossTreeConstraint cons = new CrossTreeConstraint(id, type, idA, idB);
            return cons;
        }
        #endregion

        #region Equals
        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            CrossTreeConstraint cons = obj as CrossTreeConstraint;
            if (cons == null)
            {
                return false;
            }

            return this._type == cons._type
                && this._nodeIdA.Equals(cons._nodeIdA)
                && this._nodeIdB.Equals(cons._nodeIdB);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
        #endregion

        public override string ToString()
        {
            return string.Format("{0} {1} {2}"
                , this.NodeA.FeatureName
                , this.Type.ToString()
                , this.NodeB.FeatureName);
        }

        #region Message & Warning
        /// <summary>
        /// Exist Error
        /// </summary>
        public bool ExistError { get { return _existError; } }
        /// <summary>
        /// Error Message
        /// </summary>
        public ErrorType[] ErrorMessages { get { return _errorMessages.ToArray<ErrorType>(); } }
        /// <summary>
        /// Clear Error Message
        /// </summary>
        public void ClearErrorMessages()
        {
            _existError = false;
            _errorMessages.Clear();
        }
        /// <summary>
        /// Add Error Message
        /// </summary>
        /// <param name="msg"></param>
        public void AddErrorMessage(ErrorType msg)
        {
            _existError = true;
            _errorMessages.Add(msg);
        }
        /// <summary>
        /// Exist Warning
        /// </summary>
        public bool ExistWarning { get { return _existWarning; } }
        /// <summary>
        /// Clear Warning Messages
        /// </summary>
        public void ClearWarningMessages()
        {
            _existWarning = false;
            _warningMessages.Clear();
        }
        /// <summary>
        /// Add Warning Message
        /// </summary>
        /// <param name="msg"></param>
        public void AddWarningMessage(WarningType msg)
        {
            _existWarning = true;
            _warningMessages.Add(msg);
        }
        /// <summary>
        /// Warning Messages
        /// </summary>
        public WarningType[] WarningMessages { get { return this._warningMessages.ToArray<WarningType>(); } }
        #endregion

    }
}
